package com.photoeditor.demo.ui.widget;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Keep;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.common.base.utils.DeviceUtils;
import com.photoeditor.R;
import com.photoeditor.demo.model.image.collage.util.MathUtil;
import com.photoeditor.demo.util.ImageRectUtils;


/**
 * 这个View 实现了微调整 和旋转
 */
public class RotationImageView extends ImageView {

    //当前旋转的角度
    private float mMicroRotation;

    //当前的图片
    private Bitmap mSrcBitmap;

    //是否初始化
    private boolean mIsInit;

    //裁剪的rect
    private RectF mCropRect;

    //Support 基础的rect
    private RectF mSupportRect;

    private Paint mBorderPaint;

    private Paint mLinePaint;

    //盖在上面的颜色
    private int mCoverColor;

//    private Paint mCoverPaint;

    private int mBorderWidth;

    private int mLineWidth;

    private int mSingleBlockSize;

    private Matrix mSupportMatrix;

    private Matrix mRotationMatrix;

    private Matrix mCacheMatrix;

    private Matrix mDrawMatrix;

    //View 的Rect
    private RectF mViewRect;

    private float[] mLinePosition;

    //用于更新视图
    public static final int DO_ON_DRAW = 0x101;

//    //绘制灰色的区域1  是相对于这个ImageView的  其他的RectF都是相对于整个屏幕的全局的
//    private RectF mGray1Rect;
//    //绘制灰色的区域2  是相对于这个ImageView的
//    private RectF mGray2Rect;
//    private RectF mGray1RectInvert;
//    private RectF mGray2RectInvert;

    //处理更新
    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        public void handleMessage(android.os.Message msg) {
            if (msg.what == DO_ON_DRAW) {
                postInvalidate();
            }
        }

        ;
    };

    public RotationImageView(Context context) {
        this(context, null);
    }

    public RotationImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RotationImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setScaleType(ScaleType.MATRIX);
        initialize();
    }

    private void initialize() {
//        setLayerType(LAYER_TYPE_SOFTWARE, null);
        //半透明的Cover
        mCoverColor = getContext().getResources().getColor(R.color.white_top_mask_color);
        mBorderWidth = DeviceUtils.dip2px(getContext(), 2);
        mLineWidth = 1;
        mSingleBlockSize = getResources().getDimensionPixelSize(R.dimen.raotation_view_single_size);
        mSupportMatrix = new Matrix();
        mRotationMatrix = new Matrix();
        mCacheMatrix = new Matrix();
        mDrawMatrix = new Matrix();
        mSupportRect = new RectF();
//        mGray1Rect = new RectF();
//        mGray2Rect = new RectF();
//        mGray1RectInvert = new RectF();
//        mGray2RectInvert = new RectF();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (!mIsInit && mSrcBitmap != null && !mSrcBitmap.isRecycled()) {
            init(ImageRectUtils.getViewRect(this));
        }
    }

    /**
     * 初始化一些数据
     */
    private void init(RectF viewRect) {
        if (!mIsInit) {
            mIsInit = true;
            if (mBorderPaint == null) {
                mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mBorderPaint.setStyle(Paint.Style.STROKE);
                mBorderPaint.setStrokeWidth(mBorderWidth);
                mBorderPaint.setColor(Color.WHITE);

                mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mLinePaint.setStrokeWidth(mLineWidth);
                mLinePaint.setColor(Color.WHITE);

//                mCoverPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//                mCoverPaint.setColor(mCoverColor);
//                mCoverPaint.setStyle(Paint.Style.FILL);
            }
            mViewRect = viewRect;
            countDrawableInitPosition(viewRect);
            int sizeX = (int) (mSupportRect.width() / mSingleBlockSize);
            int sizeY = (int) (mSupportRect.height() / mSingleBlockSize);
            int count = sizeX + sizeY;
            mLinePosition = new float[count * 4];
            int cache;
            for (int i = 0; i < sizeX; i++) {
                cache = i * 4;
                mLinePosition[cache] = mSupportRect.left - mViewRect.left + (i + 1) * mSingleBlockSize;
                mLinePosition[cache + 1] = mSupportRect.top - mViewRect.top;
                mLinePosition[cache + 2] = mSupportRect.left - mViewRect.left + (i + 1) * mSingleBlockSize;
                mLinePosition[cache + 3] = mSupportRect.bottom - mViewRect.top;
            }
            for (int i = sizeX; i < count; i++) {
                cache = i * 4;
                mLinePosition[cache] = mSupportRect.left - mViewRect.left;
                mLinePosition[cache + 1] = mSupportRect.top - mViewRect.top + (i - sizeX + 1) * mSingleBlockSize;
                mLinePosition[cache + 2] = mSupportRect.right - mViewRect.left;
                mLinePosition[cache + 3] = mSupportRect.top - mViewRect.top + (i - sizeX + 1) * mSingleBlockSize;
            }

            mDrawMatrix.reset();
            mDrawMatrix.set(mSupportMatrix);
            setImageMatrix(mDrawMatrix);
            setMicroRotation(mMicroRotation);
        }
    }

    /**
     * 设置旋转的角度
     */
    public void setMicroRotation(float rotation) {
        if (mIsInit) {
            rotation = Math.max(rotation, -45f);
            rotation = Math.min(rotation, 45f);
            mMicroRotation = rotation;
            mCacheMatrix.reset();
            mCacheMatrix.preRotate(rotation, mSupportRect.centerX() - mViewRect.left, mSupportRect.centerY() - mViewRect.top);
            float mScale = MathUtil.getCurrentScale(rotation, mSupportRect.width(), mSupportRect.height());
            mCacheMatrix.postScale(mScale, mScale, mSupportRect.centerX() - mViewRect.left, mSupportRect.centerY() - mViewRect.top);
            setImageMatrix(getDrawMatrix());
        } else {
            rotation = Math.max(rotation, -45f);
            rotation = Math.min(rotation, 45f);
            mMicroRotation = rotation;
        }
    }


    /**
     * 获取当前的View
     *
     * @return
     */
    private Matrix getDrawMatrix() {
        /**
         * 先设置成基础的然后 乘以后续的
         */
        mDrawMatrix.reset();
        mDrawMatrix.set(mSupportMatrix);
        mDrawMatrix.postConcat(mRotationMatrix);
        mDrawMatrix.postConcat(mCacheMatrix);
        return mDrawMatrix;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        if (mSrcBitmap == null || mSrcBitmap != bm) {
            mIsInit = false;
        }
        mSrcBitmap = bm;
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (drawable instanceof BitmapDrawable) {
            Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
            if (mSrcBitmap == null || mSrcBitmap != bm) {
                mIsInit = false;
            }
            mSrcBitmap = bm;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mIsInit) {
            int count = canvas.save();
            canvas.concat(mRotationMatrix);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                int count1 = canvas.save();
//                canvas.clipRect(0, 0, mViewRect.right - mViewRect.left, mViewRect.bottom - mViewRect.top, Region.Op.INTERSECT);
                canvas.clipRect(mCropRect.left - mViewRect.left, mCropRect.top - mViewRect.top, mCropRect.right - mViewRect.left, mCropRect.bottom - mViewRect.top, Region.Op.DIFFERENCE);
                canvas.drawColor(mCoverColor);
                canvas.restoreToCount(count1);
            }
            //+- mBorderWidth / 2 的作用是让Border显示完全
            canvas.drawRect(mCropRect.left - mViewRect.left + mBorderWidth / 2, mCropRect.top - mViewRect.top + mBorderWidth / 2,
                    mCropRect.right - mViewRect.left - mBorderWidth / 2, mCropRect.bottom - mViewRect.top - mBorderWidth / 2, mBorderPaint);
            canvas.drawLines(mLinePosition, mLinePaint);
            canvas.restoreToCount(count);

//            if(Math.abs(mDegree) == 90f || Math.abs(mDegree) == 270f){
//                canvas.drawRect(mGray1RectInvert, mCoverPaint);
//                canvas.drawRect(mGray2RectInvert, mCoverPaint);
//            } else if(Math.abs(mDegree) == 0f || Math.abs(mDegree) == 180f || Math.abs(mDegree) == 360f){
//                canvas.drawRect(mGray1Rect, mCoverPaint);
//                canvas.drawRect(mGray2Rect, mCoverPaint);
//            } else{
//                canvas.drawColor(mCoverColor);
//            }
        }
    }

    /**
     * 这个方法要在Init后调用
     * 这个方法用于计算初始化矩阵该有的大小
     */
    private void countDrawableInitPosition(RectF viewRect) {
        if (!mIsInit) {
            return;
        }
        if (mCropRect == null) {
            mCropRect = new RectF();
        }
        float width = mSrcBitmap.getWidth();
        float height = mSrcBitmap.getHeight();

        float vW = viewRect.width();
        float vH = viewRect.height();

        float w, h;

        if (width / height > vW / vH) {//宽顶着
            w = vW;
            h = w / width * height;
        } else {//高顶着
            h = vH;
            w = h / height * width;
        }

        mCropRect.left = (vW - w) / 2 + viewRect.left;
        mCropRect.top = (vH - h) / 2 + viewRect.top;
        mCropRect.right = mCropRect.left + w;
        mCropRect.bottom = mCropRect.top + h;

        mSupportRect.set(mCropRect);

        mSupportMatrix.reset();

        /**
         * fit center
         */
        mSupportMatrix.setRectToRect(new RectF(0, 0, width, height), new RectF(0, 0, vW, vH), Matrix.ScaleToFit.CENTER);

        mDealMatrix.set(mSupportMatrix);
    }


    public void refresh() {
        if (!mHandler.hasMessages(DO_ON_DRAW)) {
            mHandler.sendEmptyMessage(DO_ON_DRAW);
        }
    }

    /**
     * 获取支持的Matrix
     *
     * @return
     */
    public Matrix getSupportMatrix() {
        return mSupportMatrix;
    }

    /**
     * 获取当前操作引起的Matrix
     *
     * @return
     */
    public Matrix getCacheMatrix() {
        return mCacheMatrix;
    }

    /**
     * 重置
     */
    public void restoreImageView() {
        if (mObjectAnimator != null) {
            mObjectAnimator.end();
        }
        if (mFilpAnimator != null) {
            mFilpAnimator.end();
        }
        mTrueDegree = 0;
        mCurrentScale = 1f;
        mValue = 1;
        mDegree = 0;
        mDegreeX = 0;
        mDegreeY = 0;
        mFlipVertical = 1f;
        mFlipHorizontal = 1f;
        mMicroRotation = 0;
        mCacheMatrix.reset();
        mRotationMatrix.reset();
        mDealMatrix.set(mSupportMatrix);
        mDrawMatrix.set(mSupportMatrix);
        setImageMatrix(mDrawMatrix);
    }

    /**
     * 获取当前微调整的角度
     *
     * @return
     */
    public float getMicroRotation() {
        return mMicroRotation;
    }

    /**
     * 获取当前Bitmap的
     *
     * @return
     */
    public Bitmap getBitmap() {
        return mSrcBitmap;
    }


    /**
     * 获取当前微调整后的图片
     *
     * @return
     */
    public Bitmap getCurrentBitmap() {
        int bw = getBitmap().getWidth();
        int bh = getBitmap().getHeight();
        Matrix firstMatrix = new Matrix();
        firstMatrix.postRotate(mTrueDegree, bw / 2, bh / 2);
        firstMatrix.postScale(1, mDegreeX == 180 ? -1 : 1, bw / 2, bh / 2);
        firstMatrix.postScale(mDegreeY == 180 ? -1 : 1, 1, bw / 2, bh / 2);

        {
            int cbh = getBitmap().getWidth();
            int cbw = getBitmap().getHeight();
            int absDegrees = Math.abs((int) mTrueDegree);
            if (cbw < getWidth() && cbh < getHeight() && (absDegrees == 90 || absDegrees == 270)) {//这种情况需要转向
                float w;
                float h;
                w = getWidth();
                h = w * ((float) cbh / (float) cbw);
                if (h > getHeight()) {
                    h = getHeight();
                    w = h * ((float) cbw / (float) cbh);
                }
                firstMatrix.postScale(w / cbw, h / cbh);
            }
        }

        //这个图片是翻转和旋转后的
        Bitmap result = Bitmap.createBitmap(getBitmap(), 0, 0, bw, bh, firstMatrix, true);

        float rotation = getMicroRotation();
        float scale = MathUtil.getCurrentScale(rotation, bw, bh);

        float degree = Math.abs(mTrueDegree) % 360;
        if (degree == 90f || degree == 270f) {
            int cache = bw;
            bw = bh;
            bh = cache;
        }

        Matrix cacheMatrix = new Matrix();
        cacheMatrix.preRotate(rotation, bw / 2, bh / 2);
        cacheMatrix.postScale(scale, scale, bw / 2, bh / 2);

        Bitmap bitmap = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888);

        Canvas c = new Canvas(bitmap);
        c.setMatrix(cacheMatrix);
        c.drawBitmap(result, 0.0f, 0.0f, null);

        return bitmap;
    }


    //下面四个是临时的值
    //用于记录当前旋转的角度
    private float mDegree = 0;

    private float mFlipVertical = 1f;

    private float mFlipHorizontal = 1f;

    private float mCurrentScale = 1f;


    //下面四个是真实的值
    //用于记录当前上下翻转的角度
    private float mDegreeX = 0;

    //用于记录当前左右翻转的角度
    private float mDegreeY = 0;

    private float mTrueDegree = 0;

    private float mValue = 1;

    private Matrix mDealMatrix = new Matrix();
    private ObjectAnimator mObjectAnimator;
    private ObjectAnimator mFilpAnimator;
    private int mFlipDuration = 300;
    private int mRotationDuration = 200;


    public void rotationImageView(int degrees) {
        if (!mIsInit) {
            return;
        }
        if ((mDegreeX == 180 && mDegreeY != 180) || (mDegreeX != 180 && mDegreeY == 180)) {
            degrees = -degrees;
        }

        Drawable mDrawable = getDrawable();
        //真实宽高
        int bitmapW = mDrawable.getIntrinsicWidth();
        int bitmapH = mDrawable.getIntrinsicHeight();
        float[] values1 = new float[10];

        //这里的Matrix 如果包含旋转获取0  4 位置就会不正确
        mDealMatrix.getValues(values1);
        //旋转前当前显示的宽高
        float bw = (bitmapW * values1[0]);
        float bh = (bitmapH * values1[4]);

        //下面是计算旋转后的宽高
        degrees = degrees % 360;
        int d = (int) ((mTrueDegree + degrees) % 360);
        int absDegrees = Math.abs(d);
        if ((absDegrees == 90 || absDegrees == 270)) {
            float temp = bh;
            bh = bw;
            bw = temp;
        }

        PropertyValuesHolder pvs = null;
//        PropertyValuesHolder pvsX = null;
//        PropertyValuesHolder pvsY = null;
        if (bw > getWidth() || bh > getHeight()) {//这种情况需要缩小
            float w;
            float h;
            w = getWidth();
            h = w * ((float) bh / (float) bw);
            if (h > getHeight()) {
                h = getHeight();
                w = h * ((float) bw / (float) bh);
            }
            if (mValue != 1) {//1.x->1缩小
                float sx = bw / w;
                float sy = bh / h;
                mValue = 1f;
                mDealMatrix.postScale(1.0f / sx, 1.0f / sy);

                pvs = PropertyValuesHolder.ofFloat("currentScale", sx, 1f);
//                pvsX = PropertyValuesHolder.ofFloat("scaleX", sx, 1f);
//                pvsY = PropertyValuesHolder.ofFloat("scaleY", sy, 1f);
            } else {//1->0.x缩小
                float sx = w / bw;
                float sy = h / bh;
                mValue = sx;
                mDealMatrix.postScale(sx, sy);

                pvs = PropertyValuesHolder.ofFloat("currentScale", 1f, sx);
//                pvsX = PropertyValuesHolder.ofFloat("scaleX", 1f, sx);
//                pvsY = PropertyValuesHolder.ofFloat("scaleY", 1f, sy);
            }

        } else if (bw < getWidth() && bh < getHeight()) {//这种情况需要放大
            float w;
            float h;
            w = getWidth();
            h = w * ((float) bh / (float) bw);
            if (h > getHeight()) {
                h = getHeight();
                w = h * ((float) bw / (float) bh);
            }
            if (mValue == 1) {//1->1.x放大
                float sx = w / bw;
                float sy = h / bh;
                mValue = sx;
                mDealMatrix.postScale(sx, sy);

                pvs = PropertyValuesHolder.ofFloat("currentScale", 1f, sx);
//                pvsX = PropertyValuesHolder.ofFloat("scaleX", 1f, sx);
//                pvsY = PropertyValuesHolder.ofFloat("scaleY", 1f, sy);
            } else {//0.x->1放大
                float sx = bw / w;
                float sy = bh / h;
                mValue = 1f;
                mDealMatrix.postScale(1.0f / sx, 1.0f / sy);

                pvs = PropertyValuesHolder.ofFloat("currentScale", sx, 1f);
//                pvsX = PropertyValuesHolder.ofFloat("scaleX", sx, 1f);
//                pvsY = PropertyValuesHolder.ofFloat("scaleY", sy, 1f);
            }
        }
        if (mObjectAnimator != null) {
            mObjectAnimator.end();
        }
        if (pvs != null) {
            PropertyValuesHolder rotation = PropertyValuesHolder.ofFloat("degree", mTrueDegree, mTrueDegree + degrees);
            mObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this, rotation, pvs).setDuration(mRotationDuration);
            mObjectAnimator.start();
        } else {
            mObjectAnimator = ObjectAnimator.ofFloat(this, "degree", mTrueDegree, mTrueDegree + degrees).setDuration(mRotationDuration);
            mObjectAnimator.start();
        }
        mTrueDegree = (mTrueDegree + degrees) % 360;
    }

    /**
     * 翻转
     *
     * @param isHorizontal
     */
    public void flipImageView(boolean isHorizontal) {
        if (!mIsInit) {
            return;
        }
        if (mFilpAnimator != null) {
            mFilpAnimator.end();
        }
        if (!isHorizontal) {
            int value = mDegreeX % 360 == 0f ? 1 : -1;
            mFilpAnimator = ObjectAnimator.ofFloat(this, "flipVertical", value, -value).setDuration(mFlipDuration);
            mFilpAnimator.start();
            mDegreeX = (mDegreeX + 180f) % 360;
        } else {
            int value = mDegreeY % 360 == 0f ? 1 : -1;
            mFilpAnimator = ObjectAnimator.ofFloat(this, "flipHorizontal", value, -value).setDuration(mFlipDuration);
            mFilpAnimator.start();
            mDegreeY = (mDegreeY + 180f) % 360;
        }
    }

    public float getDegree() {
        return mDegree;
    }

    @Keep
    public void setDegree(float degree) {
        if (!mIsInit) {
            return;
        }
        this.mDegree = degree;
        mRotationMatrix.reset();
        mRotationMatrix.postRotate(mDegree, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mCurrentScale, mCurrentScale, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(1, mFlipVertical, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mFlipHorizontal, 1, mViewRect.width() / 2, mViewRect.height() / 2);
        setImageMatrix(getDrawMatrix());
    }

    public float getCurrentScale() {
        return mCurrentScale;
    }

    public void setCurrentScale(float scale) {
        this.mCurrentScale = scale;
        mRotationMatrix.reset();
        mRotationMatrix.postRotate(mDegree, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mCurrentScale, mCurrentScale, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(1, mFlipVertical, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mFlipHorizontal, 1, mViewRect.width() / 2, mViewRect.height() / 2);
        setImageMatrix(getDrawMatrix());
    }

    public float getFlipHorizontal() {
        return mFlipHorizontal;
    }

    @Keep
    public void setFlipHorizontal(float mFlipHorizontal) {
        if (!mIsInit) {
            return;
        }
        this.mFlipHorizontal = mFlipHorizontal;
        mRotationMatrix.reset();
        mRotationMatrix.postRotate(mDegree, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mCurrentScale, mCurrentScale, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(1, mFlipVertical, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mFlipHorizontal, 1, mViewRect.width() / 2, mViewRect.height() / 2);
        setImageMatrix(getDrawMatrix());
    }

    public float getFlipVertical() {
        return mFlipVertical;
    }

    @Keep
    public void setFlipVertical(float mFlipVertical) {
        if (!mIsInit) {
            return;
        }
        this.mFlipVertical = mFlipVertical;
        mRotationMatrix.reset();
        mRotationMatrix.postRotate(mDegree, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mCurrentScale, mCurrentScale, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(mFlipHorizontal, 1, mViewRect.width() / 2, mViewRect.height() / 2);
        mRotationMatrix.postScale(1, mFlipVertical, mViewRect.width() / 2, mViewRect.height() / 2);
        setImageMatrix(getDrawMatrix());
    }
}
